package com.zcgame.customview.fresh

import android.content.Context
import android.graphics.*
import android.graphics.drawable.Animatable
import android.graphics.drawable.Drawable
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.OvalShape
import android.view.View
import android.view.animation.*
import android.view.animation.Interpolator
import com.zcgame.base.utils.DensityUtil
import kotlin.math.*

class MaterialProgressDrawable(context: Context, parent: View) :Drawable(),Animatable{

    private val mParent = parent
    private val mContext = context
    private val mResources = context.resources
    private var mAnimation:Animation? = null
    private var mFinishAnimation:Animation? = null
    private var rotationCount = 0f//当前旋转的圈数
    private var backgroundColor = Color.TRANSPARENT
    private var width:Double = 0.0
    private var height:Double = 0.0
    //旋转的角度
    var rotation = 0f
    private lateinit var shadow:ShapeDrawable
    companion object{
        private const val NUM_POINTS = 5f//旋转的最大圈数

        private const val DEFAULT = 1
        private const val LARGE = 0

        private const val ARROW_WIDTH = 10
        private const val ARROW_HEIGHT = 5
        private const val ARROW_OFFSET_ANGLE = 5f
        private const val ANIMATION_DURATION = 1000 * 80 / 60L

        private const val CIRCLE_DIAMETER = 40
        private const val CENTER_RADIUS = 8.75f

        private const val STROKE_WIDTH = 2.5f

        private const val CIRCLE_DIAMETER_LARGE = 56
        private const val CENTER_RADIUS_LARGE = 12.5f
        private const val STROKE_WIDTH_LARGE = 3f
        private const val ARROW_WIDTH_LARGE = 12
        private const val ARROW_HEIGHT_LARGE = 6
        private const val MAX_PROGRESS_ARC = .8f
        private const val KEY_SHADOW_COLOR = 0x1E000000
        private const val FILL_SHADOW_COLOR = 0x3D000000
        private const val SHADOW_RADIUS = 3.5f
        private const val X_OFFSET = 0f
        private const val Y_OFFSET = 1.75f
    }

    private val mCallback = object :Callback{
        override fun unscheduleDrawable(who: Drawable, what: Runnable) {
            unscheduleSelf(what)
        }

        override fun invalidateDrawable(who: Drawable) {
            invalidateSelf()
        }

        override fun scheduleDrawable(who: Drawable, what: Runnable, `when`: Long) {
            scheduleSelf(what, `when`)
        }
    }
    private val mRing  = Ring(mCallback)
    private val mAnimator = ArrayList<Animation>()
    private val LINEAR_INTERPOLATOR: Interpolator = LinearInterpolator()
    private val END_CURVE_INTERPOLATOR: Interpolator = EndCurveInterpolator()
    private val START_CURVE_INTERPOLATOR: Interpolator = StartCurveInterpolator()
    private val EASE_INTERPOLATOR: Interpolator = AccelerateDecelerateInterpolator()
    private val COLORS = intArrayOf(0xFFC93437.toInt(), 0xFF375BF1.toInt(),
            0xFFF7D23E.toInt(), 0xFF34A350.toInt())
    init {
        mRing.mColors = COLORS
        updateSizes(DEFAULT)
        setupAnimators()
    }

    private fun setupAnimators() {
        val ring = mRing
        val finishRingAnimation:Animation = object : Animation(){
            override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
                val targetRotation = floor(ring.mStartingRotation/MAX_PROGRESS_ARC)+1f
                val startTrim = ring.startingStartTrim + (ring.startingEndTrim - ring.startingStartTrim) * interpolatedTime
                ring.mStartTrim = startTrim
                val rotation = ring.mStartingRotation + (targetRotation - ring.mStartingRotation) * interpolatedTime
                ring.mRotation = rotation
                ring.mArrowScale = 1-interpolatedTime
            }
        }
        finishRingAnimation.interpolator = EASE_INTERPOLATOR
        finishRingAnimation.duration = (ANIMATION_DURATION/2)
        finishRingAnimation.setAnimationListener(object : Animation.AnimationListener{
            override fun onAnimationRepeat(animation: Animation?) {

            }

            override fun onAnimationEnd(animation: Animation?) {
                ring.gotoNextColor()
                ring.storeOriginals()
                ring.showArrow = false
                mParent.startAnimation(mAnimation)
            }

            override fun onAnimationStart(animation: Animation?) {

            }
        })

        val animation = object :Animation(){
            override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
                //初始化最小弧度
                val minProgressArc = Math.toRadians(ring.mStrokeWidth/(2 * Math.PI * ring.mRingCenterRadius))

                val minArc = MAX_PROGRESS_ARC - minProgressArc
                val endTrim = ring.startingEndTrim + (minArc * START_CURVE_INTERPOLATOR.getInterpolation(interpolatedTime))
                ring.mEndTrim = endTrim.toFloat()
                val startTrim = ring.mStartTrim + (MAX_PROGRESS_ARC * END_CURVE_INTERPOLATOR.getInterpolation(interpolatedTime))
                ring.mStartTrim = startTrim
                val rotation = ring.mStartingRotation + (0.25f * interpolatedTime)
                ring.mRotation = rotation
                val groupRotation = ((720.0f/ NUM_POINTS)*interpolatedTime) + (720f * (rotationCount/ NUM_POINTS))
                this@MaterialProgressDrawable.rotation = groupRotation
            }
        }
        animation.repeatCount = Animation.INFINITE
        animation.repeatMode = Animation.RESTART
        animation.interpolator = (LINEAR_INTERPOLATOR)
        animation.duration = ANIMATION_DURATION
        animation.setAnimationListener(object :Animation.AnimationListener{
            override fun onAnimationRepeat(animation: Animation?) {
                ring.storeOriginals()//重复之前的动作，记住相关的数据
                ring.gotoNextColor()//切换颜色
                ring.showArrow = true
                ring.mStartTrim = ring.mEndTrim
                rotationCount = (rotationCount + 1)%(NUM_POINTS)
            }

            override fun onAnimationEnd(animation: Animation?) {

            }

            override fun onAnimationStart(animation: Animation?) {
                rotationCount = 0f;
            }
        })
        mFinishAnimation = finishRingAnimation
        mAnimation = animation

    }

    override fun getIntrinsicWidth(): Int {
        return width.toInt()
    }

    override fun getIntrinsicHeight(): Int {
        return height.toInt()
    }

    private fun updateSizes(size: Int) {
        if(size == LARGE){
            setSizeParameters(CIRCLE_DIAMETER_LARGE.toDouble(), CIRCLE_DIAMETER_LARGE.toDouble(), CENTER_RADIUS_LARGE.toDouble(),
                    STROKE_WIDTH_LARGE.toDouble(), ARROW_WIDTH_LARGE.toFloat(), ARROW_HEIGHT_LARGE.toFloat())
        }else{
            setSizeParameters(CIRCLE_DIAMETER.toDouble(), CIRCLE_DIAMETER.toDouble(), CENTER_RADIUS.toDouble(), STROKE_WIDTH.toDouble(),
                    ARROW_WIDTH.toFloat(), ARROW_HEIGHT.toFloat())}
    }

    private fun setSizeParameters(progressCircleWidth: Double, progressCircleHeight: Double,
                                  centerRadius: Double, strokeWidth: Double, arrowWidth: Float,
                                  arrowHeight: Float) {
        val ring = mRing
        val metrics = mResources.displayMetrics
        val screenDensity = metrics.density
        width = progressCircleWidth * screenDensity
        height = progressCircleHeight * screenDensity
        ring.mStrokeWidth = (strokeWidth * screenDensity).toFloat()
        ring.mRingCenterRadius = (centerRadius * screenDensity)
        ring.mColorIndex = 0
        //设置箭头的外形
        ring.setArrowDimensions(arrowWidth * screenDensity,arrowHeight * screenDensity)
        ring.setInsets(width.toFloat(), height.toFloat())
    }


    /**--------------------open start---------------------**/
    fun setBackgroundColor(color:Int){
        backgroundColor = color
        mRing.mBackgroundColor = color
        setUp(width)
    }

    /**
     * [scale]设置旋转箭头的比例
     */
    fun setArrowScale(scale:Float){
        mRing.mArrowScale = scale
    }

    /**
     * [show]是否显示箭头
     */
    fun showArrow(show:Boolean){
        mRing.showArrow = show
    }

    /**
     * [rotation]设置进度条旋转圈数
     */
    fun setProgressRotation(rotation:Float){
        mRing.mRotation = rotation
    }

    /**
     * 设置刷新控件的颜色
     */
    fun setColorSchemeColors(vararg colors:Int){
        mRing.mColors = colors
        mRing.mColorIndex = 0
    }

    /**--------------------open end---------------------**/
    private fun setUp(width: Double) {
        if(backgroundColor != Color.TRANSPARENT){
            val shadowYOffset = DensityUtil.dip2px(Y_OFFSET)
            val shadowXOffset = DensityUtil.dip2px(X_OFFSET)
            val shadowRadius = DensityUtil.dip2px(SHADOW_RADIUS)
            val oval = OvalShadow(shadowRadius.toFloat(), width.toFloat())
            shadow = ShapeDrawable(oval)
            mParent.setLayerType(View.LAYER_TYPE_SOFTWARE,shadow.paint)
            shadow.paint.setShadowLayer(shadowRadius.toFloat(), shadowXOffset.toFloat(), shadowYOffset.toFloat(), KEY_SHADOW_COLOR)
        }
    }

    override fun draw(canvas: Canvas) {
        shadow.paint.color = backgroundColor
        shadow.draw(canvas)
        val saveCount = canvas.save()
        canvas.rotate(rotation,bounds.exactCenterX(),bounds.exactCenterY())
        mRing.draw(canvas,bounds)
        canvas.restoreToCount(saveCount)
    }

    override fun setAlpha(alpha: Int) {
        mRing.mAlpha = alpha
    }

    override fun getOpacity(): Int {
        return PixelFormat.TRANSLUCENT
    }

    override fun setColorFilter(colorFilter: ColorFilter?) {
        mRing.setColorFilter(colorFilter)
    }

    override fun isRunning(): Boolean {
        return false
    }

    override fun start() {
        mAnimation?.reset()
        mRing.storeOriginals()
        if (mRing.mEndTrim != mRing.mStartTrim) {
            mParent.startAnimation(mFinishAnimation)
        }else{
            mRing.mColorIndex = 0
            mRing.resetOriginal()
            mParent.startAnimation(mAnimation)
        }
    }

    override fun stop() {
        mParent.clearAnimation()
        rotation = 0f
        mRing.showArrow = false
        mRing.mColorIndex = 0
        mRing.resetOriginal()
    }

    fun setStartEndTrim(startAngle: Float, endAngle: Float) {
        mRing.mStartTrim = startAngle
        mRing.mEndTrim = endAngle
    }

    private class EndCurveInterpolator:AccelerateDecelerateInterpolator(){
        override fun getInterpolation(input: Float): Float {
            return super.getInterpolation(max(0f,(input -0.5f) * 2.0f))
        }
    }
    private class StartCurveInterpolator:AccelerateDecelerateInterpolator(){
        override fun getInterpolation(input: Float): Float {
            return super.getInterpolation(min(1f,input * 2.0f))
        }
    }
    inner class Ring(callback:Callback){



        private val mTempBounds = RectF()
        private val mArcPaint = Paint()//弧形画笔
        private val mArrowPaint = Paint()//箭头画笔
        private val mRingCallback: Callback = callback
        private val mCirclePaint = Paint()//圆形画笔
        var mRingCenterRadius:Double = 0.0
        var mStartTrim = 0.0f
        set(value){
            field = value
            invalidateSelf()
        }
        var mEndTrim = 0.0f
        set(value) {
            field = value
            invalidateSelf()
        }

        var mRotation = 0.0f
        set(value) {
            field = value
            invalidateSelf()
        }
        var mStrokeWidth = 5.0f
        set(value) {
            field = value
            mArcPaint.strokeWidth = value
            invalidateSelf()
        }
        private var mStrokeInset = 2.5f

        var mColors: IntArray? = null
        set(value) {
            field = value
            mColorIndex = 0
        }
        var startingStartTrim:Float = 0f
        var mStartingRotation:Float = 0f
        var startingEndTrim:Float = 0f
        var startingRotationTrim:Float = 0f
        var mBackgroundColor = Color.TRANSPARENT
        private var mArrowWidth : Float = 0f
        private var mArrowHeight : Float = 0f
        var mAlpha:Int = 0
        var mColorIndex :Int = 0
        var showArrow = false
        var mArrowScale = 0f
        set(value) {
            field = value
            invalidateSelf()
        }
        private lateinit var mArrow:Path
        init {
            //设置笔触模式
            mArcPaint.strokeCap = Paint.Cap.SQUARE
            //设置抗锯齿
            mArcPaint.isAntiAlias = true
            //设置笔画模式
            mArcPaint.style = Paint.Style.STROKE
            mArrowPaint.style = Paint.Style.FILL
            mArrowPaint.isAntiAlias = true
            mCirclePaint.isAntiAlias = true
        }
        private fun invalidateSelf() {
            mRingCallback.invalidateDrawable(this@MaterialProgressDrawable)
        }

        fun setInsets( width: Float, height: Float){
            val minEdge = min(width, height)
            mStrokeInset = if(mRingCenterRadius <=0 || minEdge < 0){
                ceil(mStrokeWidth / 2.0f)
            }else{
                (minEdge /2.0f - mRingCenterRadius).toFloat()
            }
        }

        fun setArrowDimensions(width:Float,height:Float){
            mArrowWidth = width
            mArrowHeight = height
        }

        /**
         * 绘制进度转轮
         */
        fun draw(c:Canvas,bounds:Rect){
            val startAngle = (mStartTrim + mRotation) * 360
            val enAngle = (mEndTrim + mRotation) * 360
            val sweepAngle = enAngle - startAngle

            if (mBackgroundColor != Color.TRANSPARENT) {
                mCirclePaint.color = mBackgroundColor
                mCirclePaint.alpha = mAlpha
                c.drawCircle(bounds.exactCenterX(),bounds.exactCenterY(), (bounds.width()/2).toFloat(),mCirclePaint)
            }
            val arcBounds = mTempBounds.apply {
                set(bounds)
                inset(mStrokeInset,mStrokeInset)
                mArcPaint.color =  mColors!![mColorIndex]
                mArcPaint.alpha = mAlpha
            }
            c.drawArc(arcBounds,startAngle,sweepAngle,false,mArcPaint)

            drawTriangle(c,startAngle,sweepAngle,bounds)
        }

        private fun drawTriangle(c: Canvas, startAngle: Float, sweepAngle: Float, bounds: Rect) {
            if(!::mArrow.isInitialized){
                mArrow = Path()
                //设置某种未知的模式
                mArrow.fillType = Path.FillType.EVEN_ODD
            }else{
                mArrow.reset()
            }

            val inset = mStrokeInset/2 * mArrowScale
            val x = mRingCenterRadius * cos(0f) + bounds.exactCenterX()
            val y = mRingCenterRadius * sin(0f) + bounds.exactCenterY()
            mArrow.moveTo(0f,0f)
            //在（0，0）到这画条线
            mArrow.lineTo(mArrowWidth * mArrowScale,0f)
            mArrow.lineTo((mArrowWidth * mArrowScale/2),(mArrowHeight * mArrowScale))
            mArrow.offset((x - inset).toFloat(), y.toFloat())
            mArrow.close()

            mArrowPaint.color = (mColors!![mColorIndex])
            mArrowPaint.alpha = mAlpha
            c.rotate(startAngle + sweepAngle - 5,bounds.exactCenterX(),bounds.exactCenterY())
            c.drawPath(mArrow,mArcPaint)
        }

        fun gotoNextColor() {
            mColorIndex = (mColorIndex + 1) % mColors!!.size
        }

        fun storeOriginals() {
            startingStartTrim = mStartTrim
            startingEndTrim = mEndTrim
            mStartingRotation = mRotation
        }

        /**
         * 重置内容
         */
        fun resetOriginal() {
            startingStartTrim = 0f
            startingEndTrim = 0f
            mStartingRotation = 0f
        }

        fun setColorFilter(colorFilter: ColorFilter?) {
            mArcPaint.colorFilter = colorFilter
        }

    }
    private inner class OvalShadow(private val shadowRadius: Float, private val circleDiameter:Float):OvalShape(){
        private val shadowPaint = Paint()
        private val radialGradient:RadialGradient = RadialGradient((circleDiameter/2),
                (circleDiameter/2),shadowRadius, intArrayOf(FILL_SHADOW_COLOR,Color.TRANSPARENT),null,
        Shader.TileMode.CLAMP)
        init {
            shadowPaint.shader = radialGradient
        }

        override fun draw(canvas: Canvas?, paint: Paint?) {
            val viewWidth: Int =bounds.width()
            val viewHeight: Int = bounds.height()
            canvas!!.drawCircle(viewWidth / 2.toFloat(), viewHeight / 2.toFloat(), (circleDiameter / 2 + shadowRadius).toFloat(),
                    shadowPaint)
            canvas.drawCircle(viewWidth / 2.toFloat(), viewHeight / 2.toFloat(), (circleDiameter / 2).toFloat(), paint!!)
        }
    }
}
